import asyncio
from common.utility import Utility

async def say_after(content: str, delay: int = 1) -> None:
    Utility.print_info(f'entered. It will delay {delay} seconds.')
    await asyncio.sleep(delay)
    Utility.print_info(content)
    Utility.print_info('exited.')

def asyncio_run():
    asyncio.run(say_after('hello', 1))
    asyncio.run(say_after('world', 2))

def asyncio_runner():
    with asyncio.Runner() as runner:
        runner.run(say_after('hello', 1))
        Utility.print_info(runner.get_loop())
        runner.run(say_after('world', 2))

async def asyncio_create_task():
    task1: asyncio.Task[None] = asyncio.create_task(say_after('hello', 1), name='task1 created by create task')
    task2: asyncio.Task[None] = asyncio.create_task(say_after('world', 2), name='task2 created by create task')
    task1.add_done_callback(task_done_callback)
    task2.add_done_callback(task_done_callback)
    await task1
    await task2

async def asyncio_task_group():
    async with asyncio.TaskGroup() as tg:
        task3: asyncio.Task[None] = tg.create_task(say_after('hello', 1), name='task3 created by task group')
        task4: asyncio.Task[None] = tg.create_task(say_after('world', 2), name='task4 created by task group')
        task3.add_done_callback(task_done_callback)
        task4.add_done_callback(task_done_callback)

def task_done_callback(task: asyncio.Task):
    Utility.print_info(f'task is done: {task.get_name()}.')

async def asyncio_gather():
    await asyncio.gather(
        say_after('hello', 1),
        say_after('world', 2),
    )

async def asyncio_eager_task_factory():
    loop = asyncio.get_running_loop()
    await asyncio.eager_task_factory(loop, say_after('hello', 1), name='eager task 1')
    await asyncio.eager_task_factory(loop, say_after('world', 2), name='eager task 2')

async def asyncio_shield_timeout(catch_exception: bool = False):
    async with asyncio.timeout(2):
        if catch_exception:
            try:
                await asyncio.shield(say_after('hello', 1))
                await asyncio.shield(say_after('world', 3))
            except asyncio.CancelledError as err:
                Utility.print_info(f'CancelledError: {err}')
            except asyncio.TimeoutError as err:
                Utility.print_info(f'TimeoutError: {err}')
        else:
            await asyncio.shield(say_after('hello', 1))
            await asyncio.shield(say_after('world', 3))


asyncio_run()
asyncio_runner()
asyncio.run(asyncio_create_task())
asyncio.run(asyncio_task_group())
asyncio.run(asyncio_gather())
asyncio.run(asyncio_eager_task_factory())
asyncio.run(asyncio_shield_timeout(True))
asyncio.run(asyncio_shield_timeout(False))